package com.gxa.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.gxa.common.ISSContent;
import com.gxa.common.R;
import com.gxa.common.ResultDTO;
import com.gxa.common.Status;
import com.gxa.common.vo.LoginUser;
import com.gxa.entity.SysMenu;
import com.gxa.entity.SysRole;
import com.gxa.entity.SysUser;
import com.gxa.mapper.SysMenuMapper;
import com.gxa.mapper.SysRoleMapper;
import com.gxa.mapper.SysSubMenuMapper;
import com.gxa.mapper.SysUserMapper;
import com.gxa.service.LoginService;
import com.gxa.utils.JwtUtils;
import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.utils.CaptchaUtil;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

/**
 * @author MacieSerenity
 */
@Service
public class LoginServiceImpl implements LoginService {

    /**
     * 用于查询用户ID并保存到Session
     */
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    SysMenuMapper sysMenuMapper;
    @Autowired
    SysSubMenuMapper sysSubMenuMapper;

    @Override
    public ResultDTO userLogin(LoginUser loginUser, HttpServletRequest request, HttpServletResponse response) {
        ResultDTO result = new ResultDTO();
        //先验证验证码是否为空
//        Boolean captchaValidate = loginUser.getCaptcha() != null && !"".equals(loginUser.getCaptcha());
        Boolean captchaValidate = true;
        if (!captchaValidate) {
            System.out.println("未输入验证码");
            result.fromStatus(Status.NON_VERIFICATION_CODE);
            return result;
        } else {
            if (true) {
                System.out.println("验证码验证成功");
                //继续
            } else {
                System.out.println("验证码验证失败");
                result.fromStatus(Status.VERIFICATION_CODE_ERROR);
                return result;
            }
        }
        //验证账号密码是否为空
        Boolean loginNameValidate = (loginUser.getUsername() != null && !"".equals(loginUser.getPassword()));
        Boolean loginPasswordValidate = (loginUser.getPassword() != null && !"".equals(loginUser.getPassword()));

        //密码账号同不为空
        if (loginNameValidate || loginPasswordValidate) {
            System.out.println("用户名密码非空验证成功！");
            //获取签发者的名称
            String issUser = ISSContent.GXA.getKey();
            try {
                //获取当前登录对象
                Subject subject = SecurityUtils.getSubject();
                //构建用户名和密码
                UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginUser.getUsername(), loginUser.getPassword());
                //执行登录方法
                subject.login(usernamePasswordToken);
                //若没有返回任何错误则视为登录成功，返回accessToken和refreshToken
                String accessToken = JwtUtils.createJwt(UUID.randomUUID().toString(), issUser, JSONObject.toJSONString(usernamePasswordToken), JwtUtils.TTMILLIS);
                //查询出ID并放到Session
//                Integer userId = sysUserMapper.getUserIdByUsername(loginUser.getUsername());
                SysUser userByUsername = sysUserMapper.getUserByUsername(loginUser.getUsername());
                //设置返回头
                response.setHeader("Authorization", accessToken);
                response.setHeader("userID", String.valueOf(userByUsername.getId()));
                //设置前端跨域可获取的Header，若没设置这个，则前端跨域请求将获取不到Token
                response.setHeader("Access-Control-Expose-Headers", "userID,Authorization");
                result.addData("data", getUserPermission(userByUsername.getId())).addData("username", userByUsername.getRealName());
                result.fromStatus(Status.SUCCESS);
            } catch (UnknownAccountException e) {
                result.fromStatus(Status.LOGIN_FAILED);
            } catch (IncorrectCredentialsException e) {
                result.fromStatus(Status.LOGIN_FAILED);
            } catch (LockedAccountException e) {
                result.fromStatus(Status.USER_LOCKED);
            } catch (AuthenticationException e) {
                result.fromStatus(Status.USER_IDENTIFY_ERROR);
            }
            return result;
        } else {
            System.out.println("用户名密码的其中一个未输入！");
            return result.fromStatus(Status.LOGIN_FAILED);
        }
    }


    private List<SysMenu> getUserPermission(Integer userId) {
        SysUser userById = sysUserMapper.getUserById(userId);
        //获取用户角色对象
        SysRole roleByUserId = sysRoleMapper.getRoleByUserId(userById.getRoleId());
        //获取用户角色ID
        List<Integer> menuIdsByRoleId = sysRoleMapper.getMenuIdsByRoleId(roleByUserId.getId());
        //判断是否有权限
        if (menuIdsByRoleId.size() == 0) {
            return null;
        }
        List<SysMenu> sysMenuByRoleIds = sysMenuMapper.getSysMenuByRoleIds(menuIdsByRoleId);
        for (int i = 0; i < sysMenuByRoleIds.size(); i++) {
            SysMenu sysMenu = sysMenuByRoleIds.get(i);
            sysMenu.setSubMenus(sysSubMenuMapper.getSubmenuByPid(sysMenu.getId()));
        }
        return sysMenuByRoleIds;
    }

    @Override
    public R returnCaptcha(HttpServletRequest request, HttpServletResponse response) {

        //生成算数验证码
        ArithmeticCaptcha arithmeticCaptcha = new ArithmeticCaptcha();
        //设置2为算数
        arithmeticCaptcha.setLen(2);
        //验证码结果
        String content = arithmeticCaptcha.text();
        //存放到Redis中
        try {
            CaptchaUtil.out(arithmeticCaptcha, request, response);
            return R.ok();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }


    @Override
    public R logOut() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return R.ok("登出成功！");
    }
}
